home *** CD-ROM | disk | FTP | other *** search
- // Copyright (C) 2001-2002 Raven Software.
- //
- // g_misc.c
-
- #include "g_local.h"
-
-
- /*QUAKED func_group (0 0 0) ?
- Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
- */
-
- /*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
- Used as a positional target for in-game calculation, like jumppad targets.
- target_position does the same thing
- */
- void SP_info_notnull( gentity_t *self )
- {
- G_SetOrigin( self, self->s.origin );
- }
-
- /*
- =================================================================================
- TeleportPlayer
- =================================================================================
- */
- void TeleportPlayer ( gentity_t *player, vec3_t origin, vec3_t angles )
- {
- gentity_t *tent;
-
- // use temp events at source and destination to prevent the effect
- // from getting dropped by a second player event
- if ( !G_IsClientSpectating ( player->client ) )
- {
- tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
- tent->s.clientNum = player->s.clientNum;
-
- tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
- tent->s.clientNum = player->s.clientNum;
- }
-
- // unlink to make sure it can't possibly interfere with G_KillBox
- trap_UnlinkEntity (player);
-
- VectorCopy ( origin, player->client->ps.origin );
- player->client->ps.origin[2] += 1;
-
- // spit the player out
- AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
- VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
- player->client->ps.pm_time = 160; // hold time
- player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
-
- // toggle the teleport bit so the client knows to not lerp
- player->client->ps.eFlags ^= EF_TELEPORT_BIT;
-
- // set angles
- SetClientViewAngle( player, angles );
-
- // kill anything at the destination
- if ( !G_IsClientSpectating ( player->client ) )
- {
- G_KillBox (player);
- }
-
- // save results of pmove
- BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
-
- // use the precise origin for linking
- VectorCopy( player->client->ps.origin, player->r.currentOrigin );
-
- if ( !G_IsClientSpectating ( player->client ) )
- {
- trap_LinkEntity (player);
- }
- }
-
-
- /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
- Point teleporters at these.
- Now that we don't have teleport destination pads, this is just
- an info_notnull
- */
- void SP_misc_teleporter_dest( gentity_t *ent )
- {
- }
-
- //===========================================================
-
- /*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16) RMG
- this model is inserted into the bsp file
- "model" arbitrary .md3 file to display
- */
- void SP_misc_model( gentity_t *ent )
- {
- #if 0
- ent->s.modelindex = G_ModelIndex( ent->model );
- VectorSet (ent->mins, -16, -16, -16);
- VectorSet (ent->maxs, 16, 16, 16);
- trap_LinkEntity (ent);
-
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
- #else
- G_FreeEntity( ent );
- #endif
- }
-
-
- /*QUAKED misc_G2model (1 0 0) (-16 -16 -16) (16 16 16)
- "model" arbitrary .glm file to display
- */
- void SP_misc_G2model( gentity_t *ent ) {
-
- #if 0
- char name1[200] = "models/players/kyle/modelmp.glm";
- trap_G2API_InitGhoul2Model(&ent->s, name1, G_ModelIndex( name1 ), 0, 0, 0, 0);
- trap_G2API_SetBoneAnim(ent->s.ghoul2, 0, "model_root", 0, 12, BONE_ANIM_OVERRIDE_LOOP, 1.0f, level.time, -1, -1);
- ent->s.radius = 150;
- // VectorSet (ent->mins, -16, -16, -16);
- // VectorSet (ent->maxs, 16, 16, 16);
- trap_LinkEntity (ent);
-
- G_SetOrigin( ent, ent->s.origin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
- #else
- G_FreeEntity( ent );
- #endif
- }
-
- //===========================================================
-
- void locateCamera( gentity_t *ent )
- {
- vec3_t dir;
- gentity_t *target;
- gentity_t *owner;
-
- owner = G_PickTarget( ent->target );
- if ( !owner )
- {
- Com_Printf( "Couldn't find target for misc_partal_surface\n" );
- G_FreeEntity( ent );
- return;
- }
- ent->r.ownerNum = owner->s.number;
-
- // frame holds the rotate speed
- if ( owner->spawnflags & 1 )
- {
- ent->s.frame = 25;
- }
- else if ( owner->spawnflags & 2 )
- {
- ent->s.frame = 75;
- }
-
- // swing camera ?
- if ( owner->spawnflags & 4 )
- {
- // set to 0 for no rotation at all
- ent->s.gametypeitems = 0;
- }
- else
- {
- ent->s.gametypeitems = 1;
- }
-
- // clientNum holds the rotate offset
- ent->s.clientNum = owner->s.clientNum;
-
- VectorCopy( owner->s.origin, ent->s.origin2 );
-
- // see if the portal_camera has a target
- target = G_PickTarget( owner->target );
- if ( target ) {
- VectorSubtract( target->s.origin, owner->s.origin, dir );
- VectorNormalize( dir );
- } else {
- G_SetMovedir( owner->s.angles, dir );
- }
-
- ent->s.eventParm = DirToByte( dir );
- }
-
- /*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
- The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
- This must be within 64 world units of the surface!
- */
- void SP_misc_portal_surface(gentity_t *ent)
- {
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- ent->r.svFlags = SVF_PORTAL;
- ent->s.eType = ET_PORTAL;
-
- if ( !ent->target )
- {
- VectorCopy( ent->s.origin, ent->s.origin2 );
- }
- else
- {
- ent->think = locateCamera;
- ent->nextthink = level.time + 100;
- }
- }
-
- /*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
- The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
- "roll" an angle modifier to orient the camera around the target vector;
- */
- void SP_misc_portal_camera(gentity_t *ent)
- {
- float roll;
-
- VectorClear( ent->r.mins );
- VectorClear( ent->r.maxs );
- trap_LinkEntity (ent);
-
- G_SpawnFloat( "roll", "0", &roll );
-
- ent->s.clientNum = roll/360.0 * 256;
- }
-
- /*QUAKED misc_bsp (1 0 0) (-16 -16 -16) (16 16 16)
- "bspmodel" arbitrary .bsp file to display
- */
- void SP_misc_bsp(gentity_t *ent)
- {
- char temp[MAX_QPATH];
- char *out;
- float newAngle;
- int tempint;
-
- G_SpawnFloat( "angle", "0", &newAngle );
- if (newAngle != 0.0)
- {
- ent->s.angles[1] = newAngle;
- }
- // don't support rotation any other way
- ent->s.angles[0] = 0.0;
- ent->s.angles[2] = 0.0;
-
- G_SpawnString("bspmodel", "", &out);
-
- ent->s.eFlags = EF_PERMANENT;
-
- // Mainly for debugging
- G_SpawnInt( "spacing", "0", &tempint);
- ent->s.time2 = tempint;
- G_SpawnInt( "flatten", "0", &tempint);
- ent->s.time = tempint;
-
- Com_sprintf(temp, MAX_QPATH, "#%s", out);
- trap_SetBrushModel( ent, temp ); // SV_SetBrushModel -- sets mins and maxs
- G_BSPIndex(temp);
-
- level.mNumBSPInstances++;
- Com_sprintf(temp, MAX_QPATH, "%d-", level.mNumBSPInstances);
- VectorCopy(ent->s.origin, level.mOriginAdjust);
- level.mRotationAdjust = ent->s.angles[1];
- level.mTargetAdjust = temp;
- level.hasBspInstances = qtrue;
- level.mBSPInstanceDepth++;
- G_SpawnString("filter", "", &out);
- strcpy(level.mFilter, out);
- G_SpawnString("teamfilter", "", &out);
- strcpy(level.mTeamFilter, out);
-
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- VectorCopy( ent->s.origin, ent->r.currentOrigin );
- VectorCopy( ent->s.angles, ent->s.apos.trBase );
- VectorCopy( ent->s.angles, ent->r.currentAngles );
-
- ent->s.eType = ET_MOVER;
-
- trap_LinkEntity (ent);
-
- trap_SetActiveSubBSP(ent->s.modelindex);
- G_SpawnEntitiesFromString(qtrue);
- trap_SetActiveSubBSP(-1);
-
- level.mBSPInstanceDepth--;
- level.mFilter[0] = level.mTeamFilter[0] = 0;
-
- if ( g_debugRMG.integer )
- {
- G_SpawnDebugCylinder ( ent->s.origin, ent->s.time2, &g_entities[0], 2000, COLOR_WHITE );
-
- if ( ent->s.time )
- {
- G_SpawnDebugCylinder ( ent->s.origin, ent->s.time, &g_entities[0], 2000, COLOR_RED );
- }
- }
- }
-
- /*QUAKED terrain (1.0 1.0 1.0) ?
- Terrain entity
- It will stretch to the full height of the brush
-
- numPatches - integer number of patches to split the terrain brush into (default 200)
- terxels - integer number of terxels on a patch side (default 4) (2 <= count <= 8)
- seed - integer seed for random terrain generation (default 0)
- textureScale - float scale of texture (default 0.005)
- heightMap - name of heightmap data image to use
- terrainDef - defines how the game textures the terrain (file is base/ext_data/*.terrain - default is grassyhills)
- instanceDef - defines which bsp instances appear
- miscentDef - defines which client models spawn on the terrain (file is base/ext_data/*.miscents)
- densityMap - how dense the client models are packed
-
- */
- void SP_terrain(gentity_t *ent)
- {
- char temp[MAX_INFO_STRING];
- char final[MAX_QPATH];
- char seed[MAX_QPATH];
- char missionType[MAX_QPATH];
- char soundSet[MAX_QPATH];
- int shaderNum, i;
- char *value;
- int terrainID;
-
- VectorClear (ent->s.angles);
- trap_SetBrushModel( ent, ent->model );
-
- // Get the shader from the top of the brush
- // shaderNum = gi.CM_GetShaderNum(s.modelindex);
- shaderNum = 0;
-
- if (RMG.integer)
- {
- // Grab the default terrain file from the RMG cvar
- trap_Cvar_VariableStringBuffer("RMG_terrain", temp, MAX_QPATH);
- Com_sprintf(final, MAX_QPATH, "%s", temp);
- AddSpawnField("terrainDef", temp);
-
- trap_Cvar_VariableStringBuffer("RMG_instances", temp, MAX_QPATH);
- Com_sprintf(final, MAX_QPATH, "%s", temp);
- AddSpawnField("instanceDef", temp);
-
- trap_Cvar_VariableStringBuffer("RMG_miscents", temp, MAX_QPATH);
- Com_sprintf(final, MAX_QPATH, "%s", temp);
- AddSpawnField("miscentDef", temp);
-
- trap_Cvar_VariableStringBuffer("RMG_seed", seed, MAX_QPATH);
- trap_Cvar_VariableStringBuffer("RMG_mission", missionType, MAX_QPATH);
-
- trap_Cvar_VariableStringBuffer("RMG_soundset", soundSet, MAX_QPATH);
- trap_SetConfigstring(CS_AMBIENT_SOUNDSETS, soundSet );
- }
-
- // Arbitrary (but sane) limits to the number of terxels
- // if((mTerxels < MIN_TERXELS) || (mTerxels > MAX_TERXELS))
- {
- // Com_printf("G_Terrain: terxels out of range - defaulting to 4\n");
- // mTerxels = 4;
- }
-
- // Get info required for the common init
- temp[0] = 0;
- G_SpawnString("heightmap", "", &value);
- Info_SetValueForKey(temp, "heightMap", value);
-
- G_SpawnString("numpatches", "400", &value);
- Info_SetValueForKey(temp, "numPatches", va("%d", atoi(value)));
-
- G_SpawnString("terxels", "4", &value);
- Info_SetValueForKey(temp, "terxels", va("%d", atoi(value)));
-
- Info_SetValueForKey(temp, "seed", seed);
- Info_SetValueForKey(temp, "minx", va("%f", ent->r.mins[0]));
- Info_SetValueForKey(temp, "miny", va("%f", ent->r.mins[1]));
- Info_SetValueForKey(temp, "minz", va("%f", ent->r.mins[2]));
- Info_SetValueForKey(temp, "maxx", va("%f", ent->r.maxs[0]));
- Info_SetValueForKey(temp, "maxy", va("%f", ent->r.maxs[1]));
- Info_SetValueForKey(temp, "maxz", va("%f", ent->r.maxs[2]));
-
- Info_SetValueForKey(temp, "modelIndex", va("%d", ent->s.modelindex));
-
- G_SpawnString("terraindef", "grassyhills", &value);
- Info_SetValueForKey(temp, "terrainDef", value);
-
- G_SpawnString("instancedef", "", &value);
- Info_SetValueForKey(temp, "instanceDef", value);
-
- G_SpawnString("miscentdef", "", &value);
- Info_SetValueForKey(temp, "miscentDef", value);
-
- Info_SetValueForKey(temp, "missionType", missionType);
-
- for(i = 0; i < MAX_INSTANCE_TYPES; i++)
- {
- trap_Cvar_VariableStringBuffer(va("RMG_instance%d", i), final, MAX_QPATH);
- if(strlen(final))
- {
- Info_SetValueForKey(temp, va("inst%d", i), final);
- }
- }
-
- // Set additional data required on the client only
- G_SpawnString("densitymap", "", &value);
- Info_SetValueForKey(temp, "densityMap", value);
-
- Info_SetValueForKey(temp, "shader", va("%d", shaderNum));
- G_SpawnString("texturescale", "0.005", &value);
- Info_SetValueForKey(temp, "texturescale", va("%f", atof(value)));
-
- // Initialise the common aspects of the terrain
- terrainID = trap_CM_RegisterTerrain(temp);
- // SetCommon(common);
-
- Info_SetValueForKey(temp, "terrainId", va("%d", terrainID));
-
- // Let the entity know if it is random generated or not
- // SetIsRandom(common->GetIsRandom());
-
- // Let the game remember everything
- level.landScapes[terrainID] = ent;
-
- // Send all the data down to the client
- trap_SetConfigstring(CS_TERRAINS + terrainID, temp);
-
- // Make sure the contents are properly set
- ent->r.contents = CONTENTS_TERRAIN;
- ent->r.svFlags = SVF_NOCLIENT;
- ent->s.eFlags = EF_PERMANENT;
- ent->s.eType = ET_TERRAIN;
-
- // Hook into the world so physics will work
- trap_LinkEntity(ent);
-
- // If running RMG then initialize the terrain and handle team skins
- if ( RMG.integer )
- {
- trap_RMG_Init(terrainID);
-
- if ( level.gametypeData->teams )
- {
- char temp[MAX_QPATH];
-
- // Red team change from RMG ?
- trap_GetConfigstring ( CS_GAMETYPE_REDTEAM, temp, MAX_QPATH );
- if ( Q_stricmp ( temp, level.gametypeTeam[TEAM_RED] ) )
- {
- level.gametypeTeam[TEAM_RED] = trap_VM_LocalStringAlloc ( temp );
- }
-
- // Blue team change from RMG ?
- trap_GetConfigstring ( CS_GAMETYPE_BLUETEAM, temp, MAX_QPATH );
- if ( Q_stricmp ( temp, level.gametypeTeam[TEAM_BLUE] ) )
- {
- level.gametypeTeam[TEAM_BLUE] = trap_VM_LocalStringAlloc ( temp );
- }
- }
- }
- }
-
- /*
- =================================================================================
- G_DebugCylinderThink
- =================================================================================
- */
- void G_DebugCylinderThink ( gentity_t* ent )
- {
- vec3_t vec1;
- vec3_t vec2;
-
- ent->nextthink = level.time + 1000;
-
- VectorCopy ( ent->parent->client->ps.origin, vec1 );
- VectorCopy ( ent->r.currentOrigin, vec2 );
-
- vec1[2] = 0;
- vec2[2] = 0;
-
- // IF we are too far away then kill it
- if ( Distance ( vec1, vec2 ) > ent->speed )
- {
- trap_UnlinkEntity ( ent );
- return;
- }
-
- trap_LinkEntity ( ent );
- }
-
- /*
- =================================================================================
- G_SpawnDebugCylinder
- =================================================================================
- */
- void G_SpawnDebugCylinder ( vec3_t origin, float radius, gentity_t* clientent, float viewRadius, int colorIndex )
- {
- gentity_t* ent;
-
- if ( !g_cheats.integer )
- {
- return;
- }
-
- ent = G_Spawn ( );
- ent->s.eType = ET_DEBUG_CYLINDER;
- ent->s.time = colorIndex;
- ent->s.time2 = (int) radius;
- ent->parent = clientent;
- ent->speed = viewRadius;
-
- VectorCopy ( origin, ent->s.origin );
- VectorCopy ( origin, ent->r.currentOrigin );
-
- ent->nextthink = level.time + 1000;
- ent->think = G_DebugCylinderThink;
-
- trap_LinkEntity ( ent );
- }
-
-
- void fx_think( gentity_t *ent )
- {
- int time;
-
- // play fx
- G_PlayEffect( ent->health, ent->s.origin, ent->pos1 );
-
- if( ent->count >= 0 ) // stops it from rolling over, yeah kinda lame...
- {
- ent->count--;
- }
-
- if( !ent->count ) // effect is suppose to play mCount times then dissapear
- {
- G_FreeEntity(ent);
- return;
- }
-
- // calc next play time
- time = (ent->wait + flrand(0.0f, ent->random)) * 1000; // need it in milliseconds
-
- ent->think = fx_think;
- ent->nextthink = level.time + time;
- }
-
-
- /*QUAKED fx_play_effect (.2 .5 .8) (-8 -8 -8) (8 8 8) START_OFF
- Plays specified effect file
-
- "effect" name of .efx file
- "wait" seconds between triggerings, default 0.3
- "random" wait variance in seconds, default 0
- "target" direction of effect, default up
- "count" plays effect this many times then deletes itself, default -1 = infinite
-
-
- START_OFF fx starts off
-
-
- */
-
- void SP_fx_play_effect(gentity_t *ent)
- {
- gentity_t *target;
- char *fxName;
-
- G_SetOrigin( ent, ent->s.origin );
-
- G_SpawnString("effect", "", &fxName);
- ent->health = G_EffectIndex(fxName);
-
- if (ent->wait == 0.0)
- {
- ent->wait = 0.3;
- }
-
- target = G_Find(0, FOFS(targetname), ent->target);
- if (target)
- {
- VectorSubtract( target->s.origin, ent->s.origin, ent->pos1 );
- VectorNormalize( ent->pos1 );
- // find angles
- vectoangles( ent->pos1, ent->r.currentAngles );
- // copy over to other angles
- VectorCopy( ent->r.currentAngles, ent->s.angles );
- VectorCopy( ent->r.currentAngles, ent->s.apos.trBase );
- }
- else
- {
- ent->pos1[0] = ent->pos1[1] = 0.0;
- ent->pos1[2] = 1.0;
- }
-
- ent->think = fx_think;
- ent->nextthink = level.time + 100;
- }
-
-
-